﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using NLog;
using System.Transactions;

namespace PUZZLEgestServer.SVC
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "UserAdministration" in both code and config file together.
    public class UserAdministration : IUserAdministration
    {
        Logger logger = LogManager.GetCurrentClassLogger();
       
        public DAL.User CreateFirstUser(DAL.User newUser)
        {
            DAL.Entities ent = new DAL.Entities(DAL.Entities.SuperAdminConnectionStringEntity);
            ent.Connection.Open();
            System.Data.Common.DbTransaction tran = ent.Connection.BeginTransaction();

            try
            {
                logger.Info("CreateFirstUser(" + newUser.name + ")");

            
                //check if there is at least the UserAdministration module present (if not the user cant be saved, because no other rights can be setted further in the app)
                DAL.Module userAdministrationModule = ent.Modules.FirstOrDefault<DAL.Module>(m => m.type == (int)DAL.Entities.ModulesType.UserAdministration);
                if (userAdministrationModule == null)
                {
                    logger.Error("The module 'UserAdministration' was not found in the data base.\nYou can not create the admin user without having this module");
                    throw new Exception("The module 'UserAdministration' was not found in the data base.\nYou can not create the admin user without having this module");
                }

                //check the user name in the data base
                if (ent.Users.FirstOrDefault<DAL.User>(u => u.name.ToLower() == newUser.name.ToLower()) != null)
                {
                    logger.Error("User allready exists with that user name");
                    throw new Exception("User allready exists with that user name");
                }

                //decrypt password (the pasword comes from the client in TDS encryption)
                string password = Util.Encryption.TripleDES.Decrypt(newUser.password);

                //create a new sql user in the database (no CUD or Alter rights on tables given)
                ent.CreateSQLUser(newUser.name, password);

                //give this user access permissions on UserAdministration module
                SetModulePermission(ent, ref newUser, true, DAL.Entities.ModulesType.UserAdministration);

                //set the MD5 password
                newUser.password = Util.Encryption.MD5.Encrypt(password);

                //add user to the context
                DAL.Entities.CUD(ent, "Users", newUser);

                //save the changes
                ent.SaveChanges(System.Data.Objects.SaveOptions.DetectChangesBeforeSave);

                tran.Commit();

                logger.Info("User " + newUser.name + " created");

                return newUser;
            }
            catch (Exception ex)
            {
                tran.Rollback();
                logger.ErrorException("Error creating first user. User was not created.",ex);
                throw ex;
            }

        }

        public DAL.User CreateUser(DAL.User newUser)
        {
            DAL.Entities ent = new DAL.Entities(DAL.Entities.SuperAdminConnectionStringEntity);
            ent.Connection.Open();
            System.Data.Common.DbTransaction tran = ent.Connection.BeginTransaction();

            try
            {
                logger.Info("CreateUser(" + newUser.name + ")");

                //check the user name in the data base
                if (ent.Users.FirstOrDefault<DAL.User>(u => u.name.ToLower() == newUser.name.ToLower()) != null)
                {
                    logger.Error("User allready exists with that user name");
                    throw new Exception("User allready exists with that user name");
                }

                //decrypt password (the pasword comes from the client in TDS encryption)
                string password = Util.Encryption.TripleDES.Decrypt(newUser.password);

                //create user in the sql database 
                ent.CreateSQLUser(newUser.name, password);

                //set the MD5 password
                newUser.password = Util.Encryption.MD5.Encrypt(password);

                //save the user object in the database
                DAL.Entities.CUD(ent, "Users", newUser);

                //save the changes
                ent.SaveChanges(System.Data.Objects.SaveOptions.DetectChangesBeforeSave);

                tran.Commit();

                logger.Info("User " + newUser.name + " created");
                return newUser;
            }
            catch (Exception ex)
            {
                tran.Rollback();
                logger.ErrorException("Error creating first user", ex);
                throw ex;
            }
        }

        public DAL.User GetUsers(DAL.User activeUser)
        {
            DAL.Entities ent = new DAL.Entities(DAL.Entities.SuperAdminConnectionStringEntity);
            return ent.Users.First();
        }

        public void SaveUsers(DAL.User activeUser, DAL.User[] users)
        {

        }

        #region NonServiceRelated

        private void SetModulePermission(DAL.Entities ent, ref DAL.User user, bool hasAccess, params DAL.Entities.ModulesType[] moduleTypes)
        {
            try
            {
                foreach (DAL.Entities.ModulesType type in moduleTypes)
                {
                    DAL.UserRight ur = user.UserRights.FirstOrDefault<DAL.UserRight>(u => u.Module != null && u.Module.id == (int)type);
                    if (ur != null)
                    {
                        if (ur.hasaccess != hasAccess)
                        {
                            ent.DropRoleMember(user.name, type.ToString());
                            if (hasAccess)
                                ent.AddRoleMember(user.name, type.ToString());
                            else 
                                ent.DropRoleMember(user.name, type.ToString());
                        }
                        ur.hasaccess = hasAccess;
                    }
                    else
                    {
                        DAL.Module module = ent.Modules.FirstOrDefault<DAL.Module>(m => m.type == (int)type);

                        if (hasAccess)
                            ent.AddRoleMember(user.name, type.ToString());
                        else
                            ent.DropRoleMember(user.name, type.ToString());

                        ur = new DAL.UserRight();
                        ur.Module = module;
                        ur.hasaccess = hasAccess;
                        user.UserRights.Add(ur);
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private void SetUserModuleTablesRights(string userName, DAL.Entities.ModulesType type )
        { 
        
        }

        #endregion
    }
}
